home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / emac16as.arc / MINTPRIM.ASM < prev    next >
Assembly Source File  |  1990-04-01  |  32KB  |  1,419 lines

  1. ;History:1121,1
  2. ;Thu Feb 22 23:32:17 1990 add logical operators: and, or, xor.
  3. ;Tue Feb 13 19:24:24 1990 add 'Read Only' to the list of read_errors.
  4. ;Thu Sep 14 23:38:27 1989 when dealing with nonexistent strings, remember whether it was active or not.
  5. ;Tue Sep 12 23:52:46 1989 gs_prim now calls dflt if the real string can't be found.
  6. ;Sun Jun 25 23:55:33 1989 try a faster string_search
  7. ;11-04-88 00:39:35 remove #(dt) and #(tm) and put in #(ct).
  8. ;10-24-88 23:08:30 change #(si) so that it maps multiple characters.
  9. ;10-01-88 17:31:20 get_number would look too far for a minus sign.
  10. ;09-18-88 23:13:15 add "string index", si_prim.
  11. ;05-15-88 20:04:09 Remove reference to non-existent buffer_free1 [kdb]
  12. ;04-19-88 23:01:23 in ll_prim, protect the data buffer by setting data_topbot.
  13. ;04-19-88 20:16:30 ll_prim didn't work with a shortage of memory.
  14. ;03-27-88 13:40:14 change getarg_filename so that it returns zr on empty filenames.
  15. ;03-14-88 23:26:08 add fullpath under dos 3.0.
  16. ;12-07-87 23:14:20 make mp_prim discard sgaps after making parameters.
  17. ;11-10-87 21:43:34 make a marker at the end of the bufseg() definition.
  18. ;09-06-87 23:27:39 in ll_prim, we're all done if we hit eof.
  19. ;09-06-87 23:07:39 use a big buffer to read libraries in.
  20. ;07-10-87 00:13:50 get rid of duplicate copy of bc_prim.
  21.     page    ,132
  22.  
  23.     .xlist
  24.     include    mintform.def
  25.     include    mint.def
  26.     include findfile.def
  27.  
  28. data    segment byte public
  29.     extrn    data_bottop: word
  30.     extrn    data_topbot: word
  31.  
  32.     extrn    fbgn:    word
  33.     extrn    fend:    word
  34.  
  35.     extrn    filename: byte, filename2: byte
  36.  
  37. size_buf    dw    ?
  38.  
  39.     public    save_stack
  40. save_stack    dw    ?
  41.  
  42.     public    read_errors
  43. read_errors    dw    read_error_1
  44.     dw    read_error_2
  45.     dw    read_error_3
  46.     dw    read_error_4
  47.     dw    read_error_5
  48.     dw    read_error_6
  49.  
  50.     public    write_errors
  51. write_errors    dw    write_error_1
  52.     dw    write_error_2
  53.     dw    write_error_3
  54.     dw    write_error_4
  55.  
  56. read_error_1    label    byte
  57. read_error_2    db    'File too large'
  58. read_error_3    db    'File not found'
  59. read_error_4    db    'End of file'
  60. read_error_5    db    'Read Only'
  61. read_error_6    label    byte
  62.  
  63. write_error_1    label    byte
  64. write_error_2    db    'Disk full'
  65. write_error_3    db    'Directory full or bad filename'
  66. write_error_4    label    byte
  67.  
  68.  
  69. environ_name    db    'env.'
  70. environ_name_len    equ    $-environ_name
  71.         db    'RUNLINE'
  72. runline_len    equ    $-environ_name
  73.  
  74. switchar_name    db    'env.SWITCHAR'
  75. switchar_len    equ    $-switchar_name
  76.  
  77. fullpath_name    db    'env.FULLPATH'
  78. fullpath_len    equ    $-fullpath_name
  79.  
  80. dflta_name    db    'dflta'
  81. dflta_len    equ    $-dflta_name
  82.  
  83. dfltn_name    db    'dfltn'
  84. dfltn_len    equ    $-dfltn_name
  85.  
  86. form_prefix_len    dw    ?        ;for use by ln prim
  87. form_prefix_ptr    dw    ?        ;...
  88.  
  89. out_of_memory_msg    db    'Not enough memory.$'
  90.  
  91. break_state    db    ?        ;=state of break checking flag.
  92.  
  93.     extrn    stackp: byte
  94.  
  95.     public    phd_seg
  96. phd_seg    dw    ?
  97.  
  98. day_of_week    db    'Sun Mon Tue Wed Thu Fri Sat     '
  99. months        db    'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec '
  100.  
  101. data    ends
  102.  
  103. code    segment byte public
  104.     assume    cs:code, ds:data, es:data
  105.  
  106.     extrn    buffer_free: near
  107.  
  108. ;starting address of program.
  109. init:
  110.     mov    ax,data
  111.     mov    ds,ax
  112.     mov    bx,es:[2]        ;get available paragraphs.
  113.     mov    phd_seg,es
  114.     mov    es,ax
  115.     cli
  116.     mov    ss,ax
  117.     mov    sp,offset stackp
  118.     sti
  119.  
  120.     mov    dx,bx
  121.     sub    dx,ax            ;compute memory between data and end.
  122.     cmp    dx,1000h        ;more than 64k?
  123.     jb    init_exit        ;no - not enough memory.
  124.     add    ax,1000h        ;start buffers at the next segment up.
  125. ;enter with ax=>first paragraph of available memory, bx=> first paragraph of
  126. ;  unavailable memory.
  127.     push    ax
  128.     push    bx
  129.     call    init_entry        ;init the machine-dependent code
  130.     pop    bx
  131.     pop    ax
  132.     call    init_all_buffers
  133.     jc    init_exit_uninit    ;no memory.
  134.     call    init_screen        ;initialize redisplay.
  135.     call    pick_init        ;initialize the mouse.
  136.  
  137.     push    ds            ;set the fatal error address.
  138.     push    cs
  139.     pop    ds
  140.     mov    dx,offset abort_fatal
  141.     mov    ax,2524h
  142.     int    21h
  143.     pop    ds
  144.  
  145.     mov    ax,33h*256+0        ;get the break state.
  146.     int    21h
  147.     mov    break_state,dl
  148.     mov    ax,33h*256+1        ;turn break checking off.
  149.     mov    dl,0
  150.     int    21h
  151.  
  152.     jmp    init_ids_first
  153. init_exit_uninit:
  154.     call    uninit_exit
  155. init_exit:
  156.     mov    dx,offset out_of_memory_msg
  157.     mov    ah,9
  158.     int    21h
  159.     mov    ax,4c01h
  160.     int    21h            ;halt because of no memory.
  161.  
  162. ;the following externs are in 'buffers'
  163.     extrn    init_all_buffers: near
  164.  
  165. ;the following externs are in 'redisp'
  166.     extrn    init_screen: near
  167.  
  168. ;the following externs are in 'pick'
  169.     extrn    pick_init: near
  170.  
  171.     extrn    init_ids_first: near    ;start mint interpreter
  172.     extrn    init_ids: near        ;restart mint interpreter
  173.     extrn    abort_fatal: near    ;fatal error handler
  174.  
  175. ;the following externs are in 'mintprim'
  176.     extrn    init_forms: near
  177.  
  178.  
  179. ;The following two externs init and uninit anything that's machine specific.
  180.     extrn    init_entry: near
  181.     extrn    uninit_exit: near
  182.  
  183.     extrn    return_form: near
  184. ;return_form updates the form pointer and jumps to return_tos.
  185. ;Enter with ds:bx ->form, cx=unused chars.
  186.  
  187.     extrn    return_null: near
  188.  
  189.     extrn    make_active: near
  190. ;make_active forces the function to be executed in active mode, and returns
  191. ;    zr if the function already was active.
  192.  
  193.     extrn    return_arg: near
  194. ;return_arg returns the argument whose number is given in cx.
  195.  
  196.     extrn    return_arg_active: near
  197. ;return_arg_active returns the argument whose number is given in cx, and makes
  198. ;    it active.
  199.  
  200.     extrn    return_string: near
  201. ;return_string returns the ALth string out of the table pointed to by bx.
  202.  
  203.     extrn    return_sicx: near
  204. ;return_sicx returns the string pointed to by si.  The length of the
  205. ;    string is given in cx.
  206.  
  207.     extrn    return_tos: near
  208. ;return_tos returns the string pointed to by the top of the stack.
  209. ;    The length of the string is the difference between di and the
  210. ;    beginning of the stirng.
  211.  
  212.     extrn    nomem: near
  213.  
  214. ;primitives here
  215.  
  216. hl_prim:
  217.     call    get_decimal_arg1    ;get the return code.
  218.     push    ax
  219.     mov    ax,33h*256+1        ;set the break state.
  220.     mov    dl,break_state
  221.     int    21h
  222.     call    uninit_exit
  223.     pop    ax
  224.     mov    ah,4ch
  225.     int    21h
  226.  
  227.  
  228. eq_prim:
  229.     call    getarg1        ;get the first argument
  230.     mov    dx,cx        ;save size of first argument
  231.     mov    di,si        ;save pointer to first argument
  232.     mov    cx,2        ;get second argument
  233.     call    getarg
  234.     cmp    cx,dx        ;lengths equal?
  235.     jne    eq_prim_1    ;no, return 4th
  236.     repe    cmpsb        ;strings equal?
  237.     jne    eq_prim_1    ;no, return 4th.
  238.     mov    cx,3
  239.     jmp    return_arg
  240. eq_prim_1:
  241.     mov    cx,4
  242.     jmp    return_arg
  243.  
  244.  
  245. nc_prim:
  246.     call    getarg1
  247.     di_points_fbgn
  248.     mov    ax,cx
  249.     jmp    return_number
  250.  
  251.  
  252. db_prim:
  253.     int    3
  254.     jmp    return_null
  255.  
  256.  
  257. ct_prim:
  258. ;Mon Nov 21 11:31:54 1983
  259.     call    getarg1_filename    ;get the filename.
  260.     jz    ct_prim_1
  261.  
  262.     mov    dx,offset filename2
  263.     mov    ah,1ah
  264.     int    21h
  265.  
  266.     mov    dx,si            ;filename in dx for find_first.
  267.     mov    ah,4eh            ;find first matching file
  268.     mov    cx,10h            ;find subdirs, too.
  269.     int    21h
  270.     jnc    ct_prim_3        ;go if we found it.
  271.     jmp    return_null
  272. ct_prim_3:
  273.     mov    ax,filename2.find_buf_time    ;get the hours
  274.     mov    cl,3
  275.     shr    ax,cl
  276.     xor    al,al
  277.     mov    si,ax
  278.  
  279.     mov    ax,filename2.find_buf_time    ;get the minutes
  280.     mov    cl,5
  281.     shr    ax,cl
  282.     and    al,3fh
  283.     xor    ah,ah
  284.     or    si,ax
  285.  
  286.     mov    ax,filename2.find_buf_time    ;get the seconds.
  287.     mov    ah,al
  288.     xor    al,al
  289.     and    ah,1fh
  290.     shl    ah,1                ;but they're twoseconds.
  291.     mov    bp,ax
  292.  
  293. ;we have hhmm in si, ssxx in bp, ddd in al.
  294.  
  295.     mov    ax,filename2.find_buf_date    ;get the months
  296.     mov    cl,3
  297.     shl    ax,cl
  298.     and    ax,0f00h
  299.     mov    dx,ax
  300.  
  301.     mov    ax,filename2.find_buf_date    ;get the days
  302.     and    ax,1fh
  303.     or    dx,ax
  304.  
  305.     mov    ax,filename2.find_buf_date    ;get the year.
  306.     shr    ah,1
  307.     mov    al,ah
  308.     xor    ah,ah
  309.     add    ax,1980
  310.     mov    cx,ax
  311.  
  312.     mov    al,7            ;use '   ' as the day of the week.
  313.  
  314. ;we have mmdd in dx, yyyy in cx.
  315.     jmp    short ct_prim_2
  316.  
  317. ct_prim_1:
  318.     mov    ah,2ch            ;get hhmm into si, ssxx into bp, ddd into al.
  319.     int    21h
  320.     mov    si,cx
  321.     mov    bp,dx
  322.  
  323.     mov    ah,2ah            ;get mmdd into dx, yyyy into cx.
  324.     int    21h
  325.  
  326. ct_prim_2:
  327. ;we have hhmm in si, ssxx in bp, ddd in al.
  328. ;we have mmdd in dx, yyyy in cx.
  329.  
  330.     di_points_fbgn
  331.  
  332.     push    cx            ;squirrel yyyy, ssxx, and hhmm away.
  333.     push    bp
  334.     push    si
  335.  
  336. ;we have mmdd in dx, ddd in al.
  337.  
  338.     xor    ah,ah            ;stuff the day of the week.
  339.     add    al,al
  340.     add    al,al
  341.     mov    si,offset day_of_week
  342.     add    si,ax
  343.     movsw
  344.     movsw
  345.  
  346.     mov    al,dh            ;get month (1..12)
  347.     dec    al
  348.  
  349.     xor    ah,ah            ;stuff the month
  350.     add    al,al
  351.     add    al,al
  352.     mov    si,offset months
  353.     add    si,ax
  354.     movsw
  355.     movsw
  356.  
  357.     mov    al,dl            ;pushed as dx (get date)
  358.     mov    bx,10            ;do all conversions in decimal.
  359.     mov    ah,0
  360.     mov    cx,2
  361.     call    put_number
  362.     mov    al,' '
  363.     stosb
  364.  
  365.     pop    bp            ;pushed as cx (get minutes)
  366.     mov    ax,bp            ;we need them in a two-byte register.
  367.  
  368.     mov    al,ah            ;get hours
  369.     mov    ah,0
  370.     mov    cx,2
  371.     call    put_number
  372.     mov    al,":"
  373.     stosb
  374.     mov    ax,bp            ;get minutes back.
  375.     mov    ah,0
  376.     mov    cx,2
  377.     call    put_number
  378.     mov    al,":"
  379.     stosb
  380.     pop    dx            ;get seconds
  381.     mov    al,dh
  382.     mov    ah,0
  383.     mov    cx,2
  384.     call    put_number
  385.     mov    al,' '
  386.     stosb
  387.  
  388.     pop    ax            ;get the year.
  389.     mov    cx,4
  390.     call    put_number
  391.     jmp    return_tos
  392.  
  393.  
  394. ;form primitives
  395.  
  396.  
  397. ds_prim:
  398.     mov    cx,2        ;get data first.
  399.     call    getarg
  400.     mov    dx,cx
  401.     mov    di,si
  402.     call    getarg1
  403.     mov    bx,0        ;reset form pointer.
  404.     call    define_form
  405.     jmp    return_null
  406.  
  407.  
  408. mp_prim:
  409.     call    getarg1
  410.     call    find_form
  411.     jc    mp_prim_2
  412.     assume    es:formSeg
  413.     mov    dx,formSeg:[bx].data_length    ;save the count of the form in dx.
  414.     lea    di,formSeg:[bx].name_offset
  415.     add    di,formSeg:[bx].name_length    ;save the pointer to the form in di.
  416.     mov    si,fbgn            ;point si at the zeroth arg.
  417.     mov    si,data:[si]        ;point si at the form name.
  418.     mov    si,data:[si]        ;point si at the first argument.
  419.     mov    ah,sgap+1        ;start with sgap 1.
  420. mp_prim_1:
  421.     cmp    si,data:[si]        ;are we pointing at fend?
  422.     je    mp_prim_3
  423.     push    si            ;save pointer to args.
  424.     mov    cx,data:[si]        ;compute length of this arg.
  425.     sub    cx,si
  426.     sub    cx,mark_overhead
  427.     add    si,mark_overhead-1    ;make si=> text of argument.
  428. ;at this point, si,cx => arg; di,dx => form.
  429.     push    di
  430.     push    dx
  431.     jcxz    mp_prim_5    ;ignore null strings.
  432. mp_prim_4:
  433.     call    string_search
  434.     jc    mp_prim_5    ;not found.  Done with this arg.
  435. ;at this point, we have found a string.  We proceed to replace it by
  436. ;the appropriate segment gap.  We have already ensured that the string
  437. ;is at least one character long.
  438.     push    cx        ;preserve cx
  439.     mov    al,ah        ;get the sgap.
  440.     stosb            ;store it.
  441. ;by the way, at this point, the relation (cx <= dx) is always true.
  442.     sub    dx,cx        ;count it, and the ones we're getting rid of.
  443.     dec    cx        ;one less to get rid of.
  444.     mov    al,sgap        ;get rid of the rest of the chars.
  445.     rep    stosb        ;cx may be zero, but it doesn't hurt.
  446.     pop    cx
  447.     jmp    mp_prim_4
  448. mp_prim_5:
  449.     pop    dx
  450.     pop    di
  451.     pop    si        ;restore pointer to args.
  452.     mov    si,[si]        ;make it point to next arg.
  453.     inc    ah        ;increment sgap to next arg.
  454.     jmp    mp_prim_1
  455. mp_prim_3:
  456.     mov    si,di        ;now prepare to crunch out the sgap's.
  457.     mov    cx,dx
  458.     mov    dx,di
  459.     jcxz    mp_prim_8
  460. mp_prim_6:
  461.     lods    es:byte ptr 0    ;get a byte from es:
  462.     cmp    al,sgap        ;discard sgaps.
  463.     je    mp_prim_7
  464.     stosb
  465. mp_prim_7:
  466.     loop    mp_prim_6
  467. mp_prim_8:
  468.     sub    di,dx        ;subtract off the base of the string.
  469.     mov    formSeg:[bx].data_length,di
  470.     esdata
  471. mp_prim_2:
  472.     jmp    return_null
  473.  
  474.  
  475. nb_prim:
  476.     call    find_arg1
  477.     dsdata
  478.     mov    cx,3
  479.     jc    nb_prim_1
  480.     mov    cx,2
  481. nb_prim_1:
  482.     jmp    return_arg
  483.     assume    ds:data, es:data
  484.  
  485.  
  486. si_prim:
  487.     mov    cx,2            ;get the character we're translating.
  488.     call    getarg
  489.     mov    di,si            ;we need it in di.
  490.     push    di            ;save this as the pointer to what we return.
  491.     jcxz    si_prim_1        ;if no characters, return null.
  492.  
  493.     push    di            ;remember arg2.
  494.     push    cx
  495.     call    find_arg1
  496.     mov    dx,cx
  497.     pop    cx
  498.     pop    di
  499.     jc    si_prim_1        ;go if it doesn't exist.
  500.     mov    bx,si            ;we need the pointer to the string
  501.     xor    ah,ah            ;  in bx.  Get ah=0 so we can compare.
  502. si_prim_2:
  503.     mov    al,es:[di]        ;get the character.
  504.     cmp    ax,dx            ;are there actually that many?
  505.     jae    si_prim_3        ;no - use the old character.
  506.     xlat                ;get the new character.
  507. si_prim_3:
  508.     stosb                ;salt the character back to where we got it.
  509.     loop    si_prim_2
  510. si_prim_1:
  511.     dsdata
  512.     jmp    return_tos
  513.  
  514.  
  515. ;default primitive is the same as the cl primitive, only we start counting
  516. ;  arguments from zero, not one.
  517. dflt:
  518.     mov    bp,0
  519.     jmp    gs_prim_entry
  520. gs_prim:
  521.     mov    bp,1
  522. gs_prim_entry:
  523.     mov    cx,bp        ;get the number of the form name arg.
  524.     di_points_fend
  525.     call    find_arg
  526.     assume    ds:formSeg
  527.     jnc    gs_prim_0    ;go if the function was found.
  528.     or    bp,bp        ;only look up dflt if it's a default.
  529.     jne    gs_prim_1
  530.     mov    si,offset dflta_name
  531.     mov    cx,dflta_len    ;try to find the default active function.
  532.     call    make_active    ;but first make it active.
  533.     je    gs_prim_00    ;okay, it's really active.
  534.     mov    si,offset dfltn_name
  535.     mov    cx,dfltn_len    ;Ahhhh, it *was* neutral - call dfltn first.
  536. gs_prim_00:
  537.     call    find_string
  538.     jc    gs_prim_1    ;go if dflt isn't found.
  539. gs_prim_0:
  540.     jcxz    gs_prim_1    ;if no characters, return null.
  541.     or    bp,bp        ;is this dflt or cl?
  542.     jne    gs_prim_2    ;cl - use specified args.
  543.     dec    bp        ;make bp+1 be the number of the form name arg.
  544. gs_prim_2:
  545.     lodsb            ;get char from form.
  546.     or    al,al        ;test it for sgapness
  547.     jge    gs_prim_3    ;go if not sgap
  548.     sub    al,sgap        ;which sgap?
  549.     jz    gs_prim_4    ;ignore sgap0's
  550.     cbw            ;we're going to be counting off ax
  551.     add    ax,bp        ;add in the first arg number.
  552.     push    ds        ;preserve pointer, count of the form
  553.     push    si
  554.     push    cx
  555.     mov    cx,ax
  556.     dsdata
  557.     call    getarg
  558.     chk_room_cnt es
  559.     rep    movsb
  560.     pop    cx        ;restore pointer, count of the form
  561.     pop    si
  562.     pop    ds
  563.     assume    ds:formSeg
  564.     jmp    gs_prim_4
  565. gs_prim_3:
  566.     chk_room es
  567.     stosb
  568. gs_prim_4:
  569.     loop    gs_prim_2
  570. gs_prim_1:
  571.     dsdata
  572.     jmp    return_tos
  573.     assume    ds:data, es:data
  574.  
  575.  
  576. go_prim:
  577.     call    find_arg1
  578.     jc    go_prim_1    ;form not found.
  579.     assume    ds:formSeg
  580.     jcxz    go_prim_2    ;no chars left.
  581.     di_points_fbgn
  582.     movsb            ;no need to check for collision with actptr.
  583.     dec    cx
  584.     jmp    return_form
  585. go_prim_2:
  586.     dsdata
  587.     mov    cx,2
  588.     jmp    return_arg_active
  589. go_prim_1:
  590.     jmp    return_null
  591.     assume    ds:data, es:data
  592.  
  593.  
  594. rs_prim:
  595.     call    find_arg1
  596.     jc    rs_prim_1
  597.     assume    ds:formSeg
  598.     mov    formSeg:[bx].form_pointer,0
  599.     dsdata
  600. rs_prim_1:
  601.     jmp    return_null
  602.     assume    ds:data, es:data
  603.  
  604.  
  605. gn_prim:
  606.     call    find_arg1
  607.     jc    gn_prim_1
  608.     assume    ds:formSeg
  609.     jcxz    gn_prim_2
  610.     push    ds        ;save pointer, count to form.
  611.     push    si
  612.     push    cx
  613.     push    bx
  614.     dsdata
  615.     mov    cx,2        ;get number of chars to call.
  616.     call    get_decimal_arg
  617.     mov    dx,ax        ;save in dx.
  618.     pop    bx
  619.     pop    cx
  620.     pop    si
  621.     pop    ds
  622.     assume    ds:formSeg
  623.     di_points_fbgn
  624.     cmp    dx,cx        ;are we trying to get more than exists?
  625.     jbe    gn_prim_3    ;no - move the requested amount.
  626.     mov    dx,cx        ;yes - truncate the count.
  627. gn_prim_3:
  628.     xchg    dx,cx        ;swap the count remaining and the get count.
  629.     sub    dx,cx        ;dec the count remaining by the get count.
  630.     chk_room_cnt es        ;check for collision
  631.     rep    movsb        ;move all the chars.
  632.     mov    cx,dx        ;return the count remaining in cx.
  633.     jmp    return_form
  634. gn_prim_2:
  635.     dsdata
  636.     mov    cx,3
  637.     jmp    return_arg_active
  638. gn_prim_1:
  639.     jmp    return_null
  640.     assume    ds:data, es:data
  641.  
  642.  
  643.  
  644. fm_prim:
  645.     call    find_arg1
  646.     jc    fm_prim_1    ;if form not found, return null.
  647.     assume    ds:formSeg
  648.     jcxz    fm_prim_2    ;if nothing to search, return two.
  649.     xchgdses
  650.     assume    ds:data, es:formSeg
  651.     push    si
  652.     mov    di,si
  653.     mov    dx,cx
  654.     mov    cx,2
  655.     call    getarg
  656. ;now si,cx => short string, di,dx => long string.
  657.     call    string_search
  658.     jc    fm_prim_3    ;if it's not found, just return arg 3.
  659. ;what we want to do now is to return the string from [tos] to [di],
  660. ;  and advance the form pointer to point after the found string.
  661.     sub    dx,cx        ;dx gets long length - short length.
  662.     pop    si
  663.     mov    cx,di        ;get the number of characters before
  664.     sub    cx,si        ;  the search string.
  665.     xchgdses
  666.     assume    ds:formSeg, es:data
  667.     di_points_fbgn    ;prepare to return a string.
  668.     chk_room_cnt es        ;make sure we have enough room.
  669.     rep    movsb
  670.     mov    cx,dx        ;return_form expects the count in cx.
  671.     jmp    return_form
  672. fm_prim_3:
  673.     add    sp,2        ;get rid of the pointer to the search string.
  674.     assume    es:formSeg    ;because of where we come from above.
  675.     esdata
  676.     mov    cx,3
  677.     jmp    return_arg_active
  678. fm_prim_2:
  679.     assume    ds:formSeg    ;because of where we come from above.
  680.     dsdata
  681.     mov    cx,3
  682.     jmp    return_arg_active
  683. fm_prim_1:
  684.     jmp    return_null
  685.     assume    ds:data, es:data
  686.  
  687.  
  688. ev_prim:
  689.     xor    si,si            ;start at the beginning of the environ.
  690. ev_prim_1:
  691.     mov    di,fbgn
  692.  
  693.     push    si            ;copy in the environ name.
  694.     mov    si,offset environ_name
  695.     mov    cx,environ_name_len
  696.     rep    movsb
  697.     pop    si
  698.  
  699.     push    ds
  700.     mov    ds,phd_seg
  701.     mov    ds,ds:[2ch]
  702. ev_prim_2:
  703.     lodsb
  704.     stosb
  705.     or    al,al
  706.     jne    ev_prim_2
  707.     pop    ds
  708.     mov    cx,di            ;compute the length of it.
  709.     sub    cx,fbgn
  710.     dec    cx            ;don't count the null.
  711.  
  712.     cmp    cx,environ_name_len    ;did we get any at all?
  713.     je    ev_prim_3        ;if none, we're done.
  714.  
  715.     push    si            ;remember the environment pointer.
  716.     mov    di,fbgn            ;make di->entire name.
  717.     mov    si,di            ;make si -> the name.
  718.     mov    al,'='            ;look for the name/data separator.
  719.     repne    scasb
  720.     mov    dx,cx            ;dx (data length) is number of chars left.
  721.     mov    cx,di            ;compute the name length.
  722.     sub    cx,si
  723.     dec    cx            ;don't count the '='.
  724.  
  725. ;define a form.  Enter with:
  726. ;    si => name
  727. ;    cx = name length
  728. ;    di => data
  729. ;    dx = data length
  730. ;    bx = form pointer.
  731.  
  732.     xor    bx,bx
  733.     call    define_form
  734.     pop    si
  735.     jmp    ev_prim_1
  736. ev_prim_3:
  737.     mov    ah,30h            ;get the dos version.
  738.     int    21h
  739.     cmp    al,3            ;the full path is only in dos 3.0.
  740.     jb    ev_prim_4
  741.  
  742.     add    si,2            ;point to the pathname.
  743.     mov    di,fbgn
  744.     push    ds
  745.     mov    ds,phd_seg
  746.     mov    ds,ds:[2ch]
  747. ev_prim_5:
  748.     lodsb
  749.     stosb
  750.     or    al,al
  751.     jne    ev_prim_5
  752.     pop    ds
  753.     mov    dx,di            ;compute the length of it.
  754.     sub    dx,fbgn
  755.     dec    dx            ;don't count the null.
  756.  
  757.     mov    di,fbgn            ;restore di again.
  758.     mov    si,offset fullpath_name
  759.     mov    cx,fullpath_len
  760.     xor    bx,bx
  761.     call    define_form
  762.  
  763. ev_prim_4:
  764.     mov    di,fbgn
  765.     mov    si,80h
  766.     push    ds
  767.     mov    ds,phd_seg
  768.     lodsb                ;get the line length.
  769.     mov    dl,al
  770.     mov    dh,0
  771.     mov    cx,dx            ;put it where movs can destroy it.
  772.     rep    movsb
  773.     pop    ds
  774.  
  775.     mov    di,fbgn            ;restore di again.
  776.     mov    si,offset environ_name
  777.     mov    cx,runline_len
  778.     xor    bx,bx
  779.     call    define_form
  780.  
  781.     mov    ax,3700h        ;get the switchar.
  782.     int    21h
  783.  
  784.     mov    di,fbgn
  785.     mov    [di],dl            ;store the switchar.
  786.     mov    dx,1            ;set the data length.
  787.  
  788.     mov    si,offset switchar_name
  789.     mov    cx,switchar_len
  790.     xor    bx,bx
  791.     call    define_form
  792.  
  793.     jmp    return_null
  794.  
  795.  
  796.     ret
  797.  
  798.  
  799. ls_prim:
  800.     di_points_fend
  801.     call    getarg1            ;get seperator and save it.
  802.     mov    bp,si            ;store the pointer to arg1 in bp
  803.     mov    dx,cx            ;store the size of arg1 in dx
  804.     mov    cx,2            ;get the form prefix.
  805.     call    getarg
  806.     mov    form_prefix_len,cx
  807.     mov    form_prefix_ptr,si
  808.     call    first_form        ;get a pointer to the first form.
  809. ;during the execution of this loop, bp->, dx = arg1, es:bx->forms.
  810. ls_prim_1:
  811.     assume    es:formSeg
  812.     je    ls_prim_2        ;no more forms, we're done.
  813.     lea    si,formSeg:[bx].name_offset    ;get the name pointer.
  814.     mov    cx,form_prefix_len
  815.     jcxz    ls_prim_3        ;zero prefixes match anything.
  816.     cmp    cx,formSeg:[bx].name_length    ;is prefix length>name length?
  817.     ja    ls_prim_4        ;yes - prefix can't match.
  818.     push    di            ;save the source pointers.
  819.     push    si
  820.     mov    di,si
  821.     mov    si,form_prefix_ptr
  822.     repe    cmpsb            ;compare the prefix to the form name.
  823.     pop    si
  824.     pop    di
  825.     jne    ls_prim_4        ;the prefixes didn't match - ignore it.
  826. ls_prim_3:
  827.     mov    cx,formSeg:[bx].name_length    ;get the name length
  828.     xchgdses
  829.     assume    ds:formSeg, es:data
  830.     chk_room_cnt es
  831.     rep    movsb            ;move the name in.
  832.     dsdata
  833.     mov    si,bp            ;get the pointer to arg1.
  834.     mov    cx,dx            ;get the size of arg1.
  835.     chk_room_cnt
  836.     rep    movsb            ;move it in.
  837. ls_prim_4:
  838.     call    next_form
  839.     jmp    ls_prim_1        ;and continue.
  840. ls_prim_2:
  841.     esdata
  842.     jmp    return_tos
  843.     assume    ds:data, es:data
  844.  
  845.  
  846. es_prim:
  847.     mov    si,fbgn        ;point si at "dd".
  848.     mov    si,[si]        ;point si at the first arg.
  849. es_prim_1:
  850.     cmp    si,[si]        ;are we pointing at fend?
  851.     je    es_prim_3
  852.     push    si        ;save pointer to args.
  853.     mov    cx,[si]        ;compute length of this arg.
  854.     sub    cx,si
  855.     sub    cx,mark_overhead
  856.     add    si,mark_overhead-1    ;make si=> text of argument.
  857.     call    find_form    ;try to find this form.
  858.     jc    es_prim_2    ;go if it didn't exist.
  859.     assume    es:formSeg
  860.     call    delete_form    ;delete the form if it did exist.
  861.     esdata
  862. es_prim_2:
  863.     pop    si        ;restore pointer to args.
  864.     mov    si,[si]        ;make it point to next arg.
  865.     jmp    es_prim_1
  866. es_prim_3:
  867.     jmp    return_null
  868.     assume    ds:data, es:data
  869.  
  870.  
  871. sl_prim:
  872.     call    getarg1_filename
  873.     mov    dx,si
  874.     mov    cx,0
  875.     mov    ah,3ch            ;create file.
  876.     int    21h
  877.     mov    bx,ax            ;remember the handle.
  878.     mov    al,2
  879.     jc    sl_prim_4
  880.     mov    si,fbgn            ;point si at the zeroth arg.
  881.     mov    si,[si]            ;point si at the form name.
  882.     mov    si,[si]            ;point si at the first search string.
  883. sl_prim_1:
  884.     cmp    si,[si]            ;are we pointing at fend?
  885.     je    sl_prim_3
  886.     push    si            ;save pointer to args.
  887.     mov    cx,[si]            ;compute length of this arg.
  888.     sub    cx,si
  889.     sub    cx,mark_overhead
  890.     add    si,mark_overhead-1    ;make si=> text of argument.
  891.     push    bx
  892.     call    find_form
  893.     mov    di,bx            ;remember where the form is.
  894.     pop    bx
  895.     jc    sl_prim_2        ;go if it isn't there.
  896.     xchgdses
  897.     assume    ds:formSeg, es:data
  898.     mov    dx,di
  899.     mov    cx,formSeg:[di].form_length
  900.     mov    ah,40h            ;write to a file
  901.     int    21h
  902.     dsdata
  903.     jnc    sl_prim_2        ;no problem.
  904.     mov    ah,3eh            ;disk full - close the file.
  905.     int    21h
  906.     mov    dx,offset filename    ;delete the file.
  907.     mov    ah,41h
  908.     int    21h
  909.     mov    al,1
  910.     jmp    short sl_prim_4
  911. sl_prim_2:
  912.     pop    si        ;restore pointer to args.
  913.     mov    si,[si]        ;make it point to next arg.
  914.     esdata
  915.     jmp    sl_prim_1
  916. sl_prim_3:
  917.  
  918.     mov    ah,3eh        ;close the file.
  919.     int    21h
  920.     mov    al,0        ;no problem.
  921. sl_prim_4:
  922.     mov    bx,offset write_errors
  923.     jmp    return_string
  924.     assume    ds:data, es:data
  925.  
  926.  
  927. ll_prim:
  928. ;Note that information about the structure 'form' is hard-coded into the
  929. ;  next routine.  We assume that 'form_length' is only two bytes long,
  930. ;  and occurs at the beginning of the structure.
  931.     call    getarg1_filename
  932.     mov    dx,si
  933.     mov    ax,3d00h        ;open file for reading.
  934.     int    21h
  935.     mov    bx,ax            ;remember the handle.
  936.     mov    al,2
  937.     jc    ll_prim_4
  938.     mov    cx,0            ;nothing in the buffer at present.
  939.     mov    si,fend            ;set the buffer pointer.
  940. ll_prim_read:
  941. ;si -> buffer (=fend), cx = count left in buffer.
  942.     mov    di,fend            ;now move the rest of the buffer down
  943.     push    cx            ;  to fend.
  944.     rep    movsb
  945.     pop    cx
  946.     mov    si,fend            ;now point to the rest of the buffer.
  947.  
  948.     mov    dx,di            ;set disk transfer address.
  949.  
  950.     push    cx
  951.     mov    cx,data_bottop        ;add in the free space.
  952.     sub    cx,di            ;subtract off the buffer address.
  953.     mov    ah,3fh            ;read from a file.
  954.     int    21h
  955.     pop    cx
  956.     jc    ll_prim_5        ;close the file - trouble reading.
  957.     or    ax,ax            ;did we hit eof?
  958.     je    ll_prim_6        ;yes - we're done.
  959.     add    cx,ax            ;add to the count the amount we read.
  960.     add    dx,ax
  961.     mov    data_topbot,dx        ;remember the highest location that we use.
  962.  
  963.     cmp    cx,[si]            ;do we have enough room to read this in?
  964.     jb    ll_prim_3        ;no - report nomem.
  965. ll_prim_1:
  966. ;si -> buffer, cx = count left in buffer.
  967.     cmp    word ptr [si],0        ;is this the end of the library?
  968.     je    ll_prim_6        ;yes - we're all done.
  969.  
  970.     push    bx            ;define this form.
  971.     push    cx
  972.     push    si
  973.     mov    cx,[si].name_length
  974.     mov    dx,[si].data_length
  975.     mov    bx,[si].form_pointer
  976.     lea    si,[si].name_offset
  977.     mov    di,si
  978.     add    di,cx            ;or [si].name_length, but cx is cheaper.
  979.     call    define_form
  980.     pop    si
  981.     pop    cx
  982.     pop    bx
  983.  
  984.     sub    cx,[si]            ;remove this one from the buffer.
  985.     add    si,[si]            ;skip past this one.
  986.  
  987.     cmp    cx,2            ;if not enough, we need to read again.
  988.     jb    ll_prim_read
  989.     cmp    cx,[si]            ;do we have that many bytes?
  990.     jb    ll_prim_read        ;if not enough, we need to read again.
  991.  
  992.     jmp    ll_prim_1
  993. ll_prim_6:
  994.     mov    ah,3eh            ;close the file.
  995.     int    21h
  996.     mov    al,0            ;all ok.
  997.     jmp    ll_prim_4        ;we destroyed the active string.
  998. ll_prim_3:
  999.     mov    ah,3eh            ;close the file.
  1000.     int    21h
  1001.     call    nomem
  1002. ll_prim_5:
  1003.     mov    ah,3eh            ;close the file.
  1004.     int    21h
  1005.     mov    al,3            ;read error.
  1006. ll_prim_4:
  1007.     mov    bx,offset read_errors
  1008.     jmp    return_string
  1009.  
  1010.  
  1011. ad_prim:
  1012.     call    get_math
  1013.     add    ax,bx
  1014.     jmp    return_number_si
  1015.  
  1016.  
  1017. su_prim:
  1018.     call    get_math
  1019.     sub    ax,bx
  1020.     jmp    return_number_si
  1021.  
  1022.  
  1023. ml_prim:
  1024.     call    get_math
  1025.     imul    bx
  1026.     jmp    return_number_si
  1027.  
  1028.  
  1029. dv_prim:
  1030.     call    get_math
  1031.     or    bx,bx
  1032.     je    dv_prim_1
  1033.     cwd
  1034.     idiv    bx
  1035. dv_prim_1:
  1036.     jmp    return_number_si
  1037.  
  1038.  
  1039. md_prim:
  1040.     call    get_math
  1041.     or    bx,bx
  1042.     je    md_prim_1
  1043.     cwd
  1044.     idiv    bx
  1045.     mov    ax,dx
  1046. md_prim_1:
  1047.     jmp    return_number_si
  1048.  
  1049.  
  1050. and_prim:
  1051.     call    get_math
  1052.     and    ax,bx
  1053.     jmp    return_number_si
  1054.  
  1055.  
  1056. or_prim:
  1057.     call    get_math
  1058.     or    ax,bx
  1059.     jmp    return_number_si
  1060.  
  1061.  
  1062. xor_prim:
  1063.     call    get_math
  1064.     xor    ax,bx
  1065.     jmp    return_number_si
  1066.  
  1067.  
  1068. gr_prim:
  1069.     call    get_math
  1070.     mov    cx,3
  1071.     cmp    ax,bx
  1072.     jg    gr_prim_1
  1073.     mov    cx,4
  1074. gr_prim_1:
  1075.     jmp    return_arg
  1076.  
  1077.  
  1078. st_prim:
  1079. ;set the syntax table.
  1080.     call    find_arg1
  1081.     assume    ds:formSeg
  1082.     jnc    st_prim_1
  1083.     mov    bx,NIL            ;if form not found, use NIL.
  1084. st_prim_1:
  1085.     call    store_syntax_table
  1086.     dsdata
  1087.     jmp    return_null
  1088.  
  1089.  
  1090. ;primitive declarations
  1091.     public    st_prim
  1092.     public    dflt
  1093.     public    hl_prim
  1094.     public    eq_prim
  1095.     public    nc_prim
  1096.     public    db_prim
  1097.     public    ct_prim
  1098. ;forms
  1099.     public    ds_prim
  1100.     public    mp_prim
  1101.     public    gs_prim
  1102.     public    go_prim
  1103.     public    gn_prim
  1104.     public    rs_prim
  1105.     public    fm_prim
  1106.     public    ev_prim
  1107.     public    ls_prim
  1108.     public    es_prim
  1109.     public    sl_prim
  1110.     public    ll_prim
  1111.     public    nb_prim
  1112.     public    si_prim
  1113. ;math
  1114.     public    ad_prim
  1115.     public    su_prim
  1116.     public    ml_prim
  1117.     public    dv_prim
  1118.     public    md_prim
  1119.     public    and_prim
  1120.     public    or_prim
  1121.     public    xor_prim
  1122.     public    gr_prim
  1123.  
  1124. ;form subroutines
  1125.     extrn    define_form: near
  1126.     extrn    delete_form: near
  1127. ;delete_form deletes the form pointed to by ds:bx.
  1128.  
  1129. ;store_syntax_table stores the form in es:bx as the syntax table.
  1130.     extrn    store_syntax_table: near
  1131.  
  1132.     extrn    first_form: near    ;returns es:bx ->first form.
  1133.     extrn    next_form: near        ;returns es:bx ->next form, zr if none.
  1134.  
  1135.     extrn    find_form: near
  1136. ;find_form returns bx pointing to the form whose name is pointed to by si.
  1137. ;    The length of the form name is given in cx.
  1138. ;    If the form doesn't exist, cy is set, otherwise cy is clear.
  1139. ;    A pointer to the form header is returned in es:bx
  1140.  
  1141.     extrn    find_arg1: near
  1142. ;find_arg1 returns bx pointing to the form whose name is given in
  1143. ;    arg1.  If the form doesn't exist, cy is set, otherwise cy is clear.
  1144. ;    ds:si points to the form data after the form pointer, and cx is the
  1145. ;    number of chars after the form pointer.
  1146.  
  1147.     extrn    find_arg: near
  1148. ;find_arg returns bx pointing to the form whose name is given in
  1149. ;    the arg specified by cx.  If the form doesn't exist, cy is
  1150. ;    set, otherwise cy is clear.  ds:si points to the form data
  1151. ;    after the form pointer, and cx is the number of chars after
  1152. ;    the form pointer.
  1153.  
  1154.  
  1155.     extrn    find_string: near
  1156. ;find_string returns bx pointing to the form whose name is specified by si,cx.
  1157. ;    If the form doesn't exist, cy is set, otherwise cy is clear.  ds:si
  1158. ;    points to the form data after the form pointer, and cx is the number
  1159. ;    of chars after the form pointer.
  1160.  
  1161.  
  1162. ;utility subroutines
  1163.  
  1164.  
  1165.     public    get_math
  1166. get_math:
  1167. ;exit with ax=first number, bx=second number, si->first arg, di->first number.
  1168.     mov    cx,2
  1169.     call    get_decimal_arg
  1170.     push    ax
  1171.     call    getarg1
  1172.     push    si
  1173.     call    get_decimal
  1174.     mov    di,si
  1175.     pop    si
  1176.     pop    bx        ;pushed as ax
  1177.     ret
  1178.  
  1179.  
  1180.     public    get_decimal_arg1
  1181. get_decimal_arg1:
  1182.     mov    cx,1
  1183. ;fall through
  1184.     public    get_decimal_arg
  1185. get_decimal_arg:
  1186.     call    getarg
  1187. ;fall through
  1188.     public    get_decimal
  1189. get_decimal:
  1190.     mov    bx,10
  1191. ;fall through
  1192.     public    get_number
  1193. get_number:
  1194. ;enter with si,cx => string containing trailing number, bx=base to convert
  1195. ;  number in.  Return number in ax, si => start of digit string.
  1196.     add    si,cx
  1197.     push    cx
  1198. get_number_1:
  1199.     dec    si
  1200.     mov    al,[si]
  1201.     sub    al,"0"            ;between 0 and "9"?
  1202.     jb    get_number_2        ;no - can't be a digit.
  1203.     cmp    al,"9"-"0"        ;between "0" and "9"?
  1204.     jbe    get_number_6        ;yes - must be a digit.
  1205.     cmp    al,"a"-"0"
  1206.     jb    get_number_8
  1207.     sub    al,"a"-"A"
  1208. get_number_8:
  1209.     cmp    al,"A"-"0"        ;between "A" and "9"?
  1210.     jb    get_number_2        ;yes - can't be a digit.
  1211.     sub    al,"A"-("0"+10)        ;convert "A" to 10
  1212. get_number_6:
  1213.     cmp    al,bl            ;a legal digit in the desired base?
  1214.     jae    get_number_2        ;no.
  1215.     loop    get_number_1
  1216.     dec    si            ;setup for pre-increment.
  1217. get_number_2:
  1218.     mov    dx,cx
  1219.     pop    cx            ;restore count.
  1220.     sub    cx,dx            ;get the actual count of chars into cx.
  1221.     push    dx            ;remember the number of characters left.
  1222.     inc    si
  1223.     push    si            ;save a copy of the start of the number.
  1224.     mov    ax,0            ;initially zero.
  1225. ;at this point, si => first digit, cx = count of digits to convert.
  1226.     jcxz    get_number_4        ;if no more chars, we're done.
  1227. get_number_3:
  1228.     mul    bx
  1229.     mov    dx,ax
  1230.     lodsb                ;ax = new ASCII digit.
  1231.     sub    al,"0"            ;make it a number.
  1232.     cmp    al,"9"-"0"
  1233.     jbe    get_number_7
  1234.     cmp    al,"a"-"0"
  1235.     jb    get_number_9
  1236.     sub    al,"a"-"A"
  1237. get_number_9:
  1238.     sub    al,"A"-("0"+10)
  1239. get_number_7:
  1240.     cbw                ;make it a word.
  1241.     add    ax,dx            ;and add in the old value.
  1242.     loop    get_number_3
  1243. get_number_4:
  1244.     pop    si
  1245.     pop    dx
  1246.     or    dx,dx            ;did we use up all the characters?
  1247.     je    get_number_5        ;yes - don't look for a minus sign.
  1248.     cmp    byte ptr -1[si],"-"
  1249.     jne    get_number_5
  1250.     dec    si
  1251.     neg    ax
  1252. get_number_5:
  1253.     ret
  1254.  
  1255.  
  1256. return_number_si:
  1257.     push    si
  1258.     public    return_number
  1259. return_number:
  1260. ;enter with di => place to put string, tos => start of string,
  1261. ;  ax=number.
  1262.     mov    cx,0            ;use only as many digits as is needed.
  1263.     mov    bx,10
  1264.     call    put_number
  1265.     jmp    return_tos
  1266.  
  1267.  
  1268.     public    put_number
  1269. put_number:
  1270. ;enter with di => place to put string, ax = number, cx=minimum number of digits
  1271. ;  bx=base to convert number to.
  1272.     or    ax,ax
  1273.     jge    put_number_1
  1274.     neg    ax
  1275.     mov    byte ptr [di],"-"
  1276.     inc    di
  1277. put_number_1:
  1278.     call    one_digit
  1279.     ret
  1280.  
  1281.  
  1282. one_digit:
  1283.     jcxz    one_digit_3
  1284.     dec    cx
  1285. one_digit_3:
  1286.     xor    dx,dx        ;unsigned number.
  1287.     div    bx
  1288.     push    dx
  1289.     or    ax,ax
  1290.     jnz    one_digit_1    ;if more digits, do them.
  1291.     jcxz    one_digit_2    ;if count is zero, don't do next digit.
  1292. ;we get here if we have more digits to do, or we have more leading
  1293. ; zeroes to place.
  1294. one_digit_1:
  1295.     call    one_digit
  1296. one_digit_2:
  1297.     pop    ax        ;pushed as dx
  1298.     add    al,"0"
  1299.     cmp    al,"9"
  1300.     jbe    one_digit_4
  1301.     add    al,"A"-("9"+1)    ;the digit above "9" becomes an "A".
  1302. one_digit_4:
  1303.     chk_room
  1304.     stosb
  1305.     ret
  1306.  
  1307.  
  1308. string_search:
  1309.  
  1310.     if    0
  1311.  
  1312. ;enter with si,cx => short string, es:di,dx => long string.
  1313. ;exit with nc if string was found, es:di,dx => position found.
  1314. ;exit with cy if string was not found.
  1315.     jcxz    string_search_3    ;zero length strings are found immediately
  1316. ;we can get into trouble if cx = 0 after this point.
  1317. string_search_1:
  1318.     cmp    dx,cx
  1319.     jb    string_search_2
  1320.     push    si    ;preserve all the registers.
  1321.     push    di
  1322.     push    cx
  1323.     repe    cmpsb
  1324.     pop    cx
  1325.     pop    di
  1326.     pop    si
  1327.     je    string_search_3
  1328.     dec    dx
  1329.     inc    di
  1330.     jmp    string_search_1
  1331. string_search_3:
  1332.     clc
  1333.     ret
  1334. string_search_2:
  1335.     stc
  1336.     ret
  1337.  
  1338.     else
  1339.  
  1340. ;enter with si,cx => short string, es:di,dx => long string.
  1341. ;exit with nc if string was found, es:di,dx => position found.
  1342. ;exit with cy if string was not found.
  1343. ;preserve si,cx, ah.
  1344.     push    bx
  1345.     jcxz    string_search_3        ;zero length strings are found immediately
  1346.     mov    bx,cx            ;save short string length.
  1347.     mov    cx,dx            ;get long string length.
  1348.     mov    dx,si            ;save short string pointer.
  1349.     dec    bx
  1350.     sub    cx,bx            ;this many fewer chars to look at.
  1351.     jb    string_search_2        ;"short" string isn't really shorter.
  1352. string_search_1:
  1353.     jcxz    string_search_2        ;no chars to look at.
  1354.     mov    si,dx
  1355.     lodsb                ;get the first char.
  1356.     repne    scasb            ;look for the first char.
  1357.     jnz    string_search_2        ;we didn't find it.
  1358.     push    cx            ;save the short length length
  1359.     push    di            ;save the long position
  1360.     mov    cx,bx            ;get cx=short string length - 1.
  1361.     or    cx,cx            ;if cx is zero, we match.
  1362.     repe    cmpsb            ;is this it?
  1363.     pop    di            ;restore the long position
  1364.     pop    cx            ;restore the short length
  1365.     jne    string_search_1        ;no match - try at next position.
  1366.  
  1367.     mov    si,dx            ;restore short pointer.
  1368.     dec    di            ;make di point to the first char again.
  1369.     inc    cx            ;and have cx be the number of chars left.
  1370.  
  1371.     add    cx,bx            ;restore the original count.
  1372.     mov    dx,cx            ;return the remaining count in dx.
  1373.  
  1374.     mov    cx,bx            ;restore short count
  1375.     inc    cx            ;restore count's original value.
  1376. string_search_3:
  1377.     pop    bx
  1378.     clc
  1379.     ret
  1380. string_search_2:
  1381.     mov    si,dx            ;restore short pointer.
  1382.     mov    cx,bx            ;restore search count
  1383.     inc    cx            ;restore count's original value.
  1384.     pop    bx
  1385.     stc
  1386.     ret
  1387.  
  1388.     endif
  1389.  
  1390.  
  1391.     public    getarg1_filename
  1392. getarg1_filename:
  1393.     mov    cx,1
  1394.     public    getarg_filename
  1395. getarg_filename:
  1396. ;return si ->filename, zr if filename is null.
  1397.     call    getarg
  1398.     mov    di,offset filename
  1399.     rep    movsb
  1400.     xor    al,al
  1401.     stosb
  1402.     mov    si,offset filename
  1403.     cmp    [si],al
  1404.     ret
  1405.  
  1406.  
  1407.     extrn    getarg1: near
  1408. ;getarg1 returns si -> the first argument.  cx is set to the size
  1409. ;    of the first argument.
  1410.  
  1411.     extrn    getarg: near
  1412. ;getarg returns si -> the argument given in cx.  cx is set to the size
  1413. ;    of the argument.
  1414.  
  1415. code    ends
  1416.  
  1417.     end    init
  1418.  
  1419.